package com.yunhoo.checkFlow.factory.impl;

import com.ibatis.sqlmap.client.SqlMapClient;
import com.yunhoo.checkFlow.factory.dao.BillCheck;
import com.yunhoo.checkFlow.model.FlowInfo;
import com.yunhoo.checkFlow.model.FlowModel;
import com.yunhoo.sys.db.util.IbatisTemplate;
import com.yunhoo.sys.util.common.LoginParam;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

public abstract class BaseCheck implements BillCheck {

    private final String NAMESPACE_FLOW = "flowInfo.";
    private String billType;
    private String checkerId;
    private String checkerRole;
    //
    private FlowModel flowModel = null;//当前审批人 节点
    private List<FlowModel> flowModelList = null;//流程列表
    private Map<String, List<FlowInfo>> allFlowInfoMap = null;//按 billNumber,将flowInfo 分开

    public BaseCheck(String billType, String checkerId, String checkerRole) {
        this.billType = billType;
        this.checkerId = checkerId;
        this.checkerRole = checkerRole;
        init();
    }

    /* 初始化 */
    private void init() {
        /* 初始化 FlowModel */
        Map map = new HashMap();
        map.put("orgCode", LoginParam.getOrg().getCode());
        map.put("iyear", LoginParam.getIyear());
        map.put("type", billType);
        map.put("checker", checkerId);
        map.put("checkRole", checkerRole);
        flowModel = (FlowModel) IbatisTemplate.query(NAMESPACE_FLOW + "queryFlowModelByCheckerAndRole", map);

        if (flowModel == null) return;

        /* 初始化 整个审批流模型 列表 */
        Map map1 = new HashMap();
        map1.put("orgCode", LoginParam.getOrg().getCode());
        map1.put("iyear", LoginParam.getIyear());
        map1.put("type", billType);
        flowModelList = IbatisTemplate.queryForList(NAMESPACE_FLOW + "queryFlowModelList", map);

        initAllInfoMap();
    }

    /* map key : billNumber --> 单据编号
     * map value : List<FlowInfo> --> billNumber 所对应的审批信息
     */
    private void initAllInfoMap() {
        List<FlowInfo> allInfoli = getFlowInfoList_all();

        allFlowInfoMap = new HashMap<String, List<FlowInfo>>();

        String number = allInfoli.get(0).getNumber();
        List<FlowInfo> tempList = new ArrayList();
        tempList.add(allInfoli.get(0));
        for (FlowInfo temp : allInfoli) {
            if (!number.equals(temp.getNumber())) {
                allFlowInfoMap.put(number, tempList);
                number = temp.getNumber();
                tempList = new ArrayList();
            }
            tempList.add(temp);
        }
        allFlowInfoMap.put(number, tempList);
    }

    private List<FlowInfo> getFlowInfoListFromMap(String billNumber) {
        List<FlowInfo> infoli = allFlowInfoMap.get(billNumber);
        if (infoli == null) infoli = new ArrayList();
        return infoli;
    }

    @Override
    public void refreshAllInfoMap() {
        initAllInfoMap();
    }

    /*
     * 在审批流中，对当前审批人来说，单据所处的状态，
     *  0：等待（审批人）审批，
     *  1：（审批人）已审批通过,
     * -2:  等待上级审批
     * 
     * -1 和 99 ：单据审批已经结束
     */
    @Override
    public String buildBillStatusForList(String number, String flowMark) {
        if ("-1".equals(flowMark)) return "-1";
        if ("99".equals(flowMark)) return "99";

        List<FlowInfo> infoli = getFlowInfoListFromMap(number);

        return billStatus(infoli);
    }

    /*
     * 在审批流中，对当前审批人来说，单据所处的状态，
     *  0：等待（审批人）审批，
     *  1：（审批人）已审批通过,
     * -2:  等待上级审批
     * 
     * -1 和 99 ：单据审批已经结束
     */
    @Override
    public String buildBillStatusForSingleBill(String number, String flowMark) {
        if ("-1".equals(flowMark)) return "-1";
        if ("99".equals(flowMark)) return "99";

        List<FlowInfo> infoli = getFlowInfoListByNumber(number);

        return billStatus(infoli);
    }

    private String billStatus(List<FlowInfo> infoli) {
        String flag;
        String isConfirm;
        String checkRole;
        int count = 0;
        List<FlowModel> levelModelList = getFlowModelListByLevel(flowModel.getCheckLevel() - 1);

        for (FlowInfo info : infoli) {
            isConfirm = info.getIsConfirm();
            checkRole = info.getCheckRole();

            /* 当前审批人 是否审批 */
            if (info.getCheckLevel().intValue() == flowModel.getCheckLevel().intValue() && checkRole.equals(flowModel.getRoleId()) && "1".equals(info.getIsConfirm())) {//已有该条目的 审批通过 记录
                flag = "1";
                return flag;
            }

            /* 当前审批人所在角色 没有审批，检测上级是否审批完成 */
            for (FlowModel model : levelModelList) {
                if (info.getCheckLevel().intValue() == flowModel.getCheckLevel().intValue() - 1 && checkRole.equals(model.getRoleId()) && "1".equals(isConfirm)) {//已有该条目的 通过记录,
                    count++;
                }
            }
        }

        /* 当前审批人所在角色 没有审批,并且 处在 第一层级 */
        if (flowModel.getCheckLevel() == 1) {
            return "0";
        }

        /* 层级通过条目 == 层级节点数 */
        if (count == levelModelList.size()) {
            flag = "0";
        } else flag = "-2";

        return flag;
    }

    /* 是最后一个审批人 */
    private boolean isLastNode(SqlMapClient client, String billNumber) throws SQLException {
        /* 审批信息通过的条数 == 审批模型 节点数量 -1  ==> 是最后一个审批人 */

        List li = getFlowInfoListInTransaction(client, billNumber);
        if (li == null || li.isEmpty()) return false;
        return li.size() == flowModelList.size() - 1;
    }

    /* 是第一个审批人 */
    private boolean isFirstNode(SqlMapClient client, String billNumber) throws SQLException {
        if (flowModel.getCheckLevel() > 1) return false;

        /* 列表为空 ==> 尚无人审批 */
        List li = getFlowInfoListInTransaction(client, billNumber);
        return (li == null || li.isEmpty());
    }

    /* 通过 */
    @Override
    public boolean pass(String billNumber, FlowInfo flowInfo) {
        flowInfo.setNumber(billNumber);
        flowInfo.setFid(flowModel.getFid());
        flowInfo.setChecker(checkerId);
        flowInfo.setIsCheck("1");
        flowInfo.setType(billType);
        flowInfo.setCheckRole(flowModel.getRoleId());
        flowInfo.setCheckLevel(flowModel.getCheckLevel());
        flowInfo.setCheckdate(new Date());

        SqlMapClient client = IbatisTemplate.getSqlMapClient();
        try {
            client.startTransaction();

            /* 更新flowMark */
            String flowMark = "50";
            if (isLastNode(client, billNumber)) {//注意：该判断 依赖 审批信息条数，因此必须在 保存审批信息之前
                flowMark = "99";//最后一个审批人，flowMark 置为 99 审批结束
            }
            updateFlowMark(client, billNumber, flowMark);

            /* 将本角色 以前的审批信息 删除 */
            Map map = new HashMap();
            map.put("orgCode", LoginParam.getOrg().getCode());
            map.put("iyear", LoginParam.getIyear());
            map.put("number", billNumber);
            map.put("type", billType);
            map.put("checkRole", flowModel.getRoleId());
            map.put("checkLevel", flowModel.getCheckLevel());
            client.delete(NAMESPACE_FLOW + "deleteFlowInfoByRole", map);

            /* 保存审批信息 */
            client.insert(NAMESPACE_FLOW + "insertFlowInfo", flowInfo);

            /* 保存审批信息 到 历史信息表 */
            client.insert(NAMESPACE_FLOW + "insertFlowInfo_history", flowInfo);

            client.commitTransaction();
        } catch (SQLException ex) {
            Logger.getLogger(BaseCheck.class.getName()).log(Level.SEVERE, null, ex);

            /* 遇到异常，返回false,注意：返回之前 finally 内的内容会执行，故不用担心会跳过finally */
            return false;
        } finally {
            try {
                client.endTransaction();
            } catch (SQLException ex) {
                Logger.getLogger(BaseCheck.class.getName()).log(Level.SEVERE, null, ex);
            }
            System.out.println(" * * * " + " finlly " + "  * * * ");
        }

        /* 程序正常结束，返回true */
        return true;
    }

    /* 退回 */
    @Override
    public boolean sendBack(String billNumber, FlowInfo flowInfo) {
        flowInfo.setNumber(billNumber);
        flowInfo.setFid(flowModel.getFid());
        flowInfo.setChecker(checkerId);
        flowInfo.setIsCheck("0");
        flowInfo.setType(billType);
        flowInfo.setCheckRole(flowModel.getRoleId());
        flowInfo.setCheckLevel(flowModel.getCheckLevel());
        flowInfo.setCheckdate(new Date());

        SqlMapClient client = IbatisTemplate.getSqlMapClient();
        try {
            client.startTransaction();

            /* 清空本层级审批信息 */
            Map map = new HashMap();
            map.put("orgCode", LoginParam.getOrg().getCode());
            map.put("iyear", LoginParam.getIyear());
            map.put("number", billNumber);
            map.put("type", billType);
            for (FlowModel fm : getFlowModelListByLevel(flowModel.getCheckLevel())) {
                map.put("fid", fm.getFid());
                client.delete(NAMESPACE_FLOW + "deleteFlowInfoByFid", map);
            }

//            /* 保存审批信息 */
//            client.insert(NAMESPACE_FLOW + "insertFlowInfo", flowInfo);

            /* 保存审批信息 到 历史信息表 */
            client.insert(NAMESPACE_FLOW + "insertFlowInfo_history", flowInfo);

            /* 更新flowMark */
            String flowMark = "50";
            if (isFirstNode(client, billNumber)) {//注意：该判断 依赖 审批信息条数，且与通过不同，必须在修改以前审批信息 isCheck = 0 之后
                flowMark = "-1";//第一个审批人，flowMark 置为 -1 单据退回给 录入人
            }
            updateFlowMark(client, billNumber, flowMark);

            /* 退回到上级节点 ==> 将上级节点 isCheck 置为 0 */
            Map map1 = new HashMap();
            map1.put("orgCode", LoginParam.getOrg().getCode());
            map1.put("iyear", LoginParam.getIyear());
            map1.put("number", billNumber);
            for (FlowModel model : getFlowModelListByLevel(flowModel.getCheckLevel() - 1)) {
                map1.put("fid", model.getFid());
                client.update(NAMESPACE_FLOW + "updateFlowInfoIsCheck", map1);
            }

            client.commitTransaction();
        } catch (SQLException ex) {
            Logger.getLogger(BaseCheck.class.getName()).log(Level.SEVERE, null, ex);

            /* 遇到异常，返回false,注意：返回之前 finally 内的内容会执行，故不用担心会跳过finally */
            return false;
        } finally {
            try {
                client.endTransaction();
            } catch (SQLException ex) {
                Logger.getLogger(BaseCheck.class.getName()).log(Level.SEVERE, null, ex);
            }
            System.out.println(" * * * " + " finlly " + "  * * * ");
        }

        /* 程序正常结束，返回true */
        return true;
    }

    /* 取消审批: 审批通过的才可以取消审批，
     *      退回的不可以取消，
     *      只有本人才可以取消审批,
     *      只有审批后没其他人进行过审批的 才可以取消
     * return -1 数据库异常
     *        -2 已有其他人进行过审批无法取消
     *        -3 本人尚未审批
     *         1 取消成功
     */
    @Override
    public int cancelCheck(String billNumber) {
        SqlMapClient client = IbatisTemplate.getSqlMapClient();
        try {
            client.startTransaction();

            /* 检查是否可 撤销审批 */
            int flag = checkIsCancelAble(client, billNumber, billType);
            if (flag != 1) return flag;

            /* 将上次前的审批信息 isConfirm ==> 3 */
            Map map = new HashMap();
            map.put("orgCode", LoginParam.getOrg().getCode());
            map.put("iyear", LoginParam.getIyear());
            map.put("number", billNumber);
            map.put("type", billType);
            map.put("fid", flowModel.getFid());
            client.delete(NAMESPACE_FLOW + "deleteFlowInfoByFid", map);

            /* 保存撤销记录，信息基本与上次一致，只是需要将 isConfirm 改为 3 */
            Map map1 = new HashMap();
            map1.put("orgCode", LoginParam.getOrg().getCode());
            map1.put("iyear", LoginParam.getIyear());
            map1.put("number", billNumber);
            map1.put("type", billType);
            map1.put("fid", flowModel.getFid());
            map1.put("checkDate", new Date());
            client.insert(NAMESPACE_FLOW + "insertFlowInfo_historyOfCancelCheck", map1);

            /* 更新flowMark */
            updateFlowMark(client, billNumber, "50");

            client.commitTransaction();
        } catch (SQLException ex) {
            Logger.getLogger(BaseCheck.class.getName()).log(Level.SEVERE, null, ex);

            /* 遇到异常，返回false,注意：返回之前 finally 内的内容会执行，故不用担心会跳过finally */
            return -1;
        } finally {
            try {
                client.endTransaction();
            } catch (SQLException ex) {
                Logger.getLogger(BaseCheck.class.getName()).log(Level.SEVERE, null, ex);
            }
            System.out.println(" * * * " + " finlly " + "  * * * ");
        }

        /* 程序正常结束，返回true */
        return 1;
    }

    private int checkIsCancelAble(SqlMapClient client, String billNumber, String billType) throws SQLException {
        /* 确认上次审批后没有其他人进行过审批 */
        Map map1 = new HashMap();
        map1.put("orgCode", LoginParam.getOrg().getCode());
        map1.put("iyear", LoginParam.getIyear());
        map1.put("type", billType);
        map1.put("number", billNumber);
        map1.put("fid", flowModel.getFid());
        Date lastCheckDate = (Date) client.queryForObject(NAMESPACE_FLOW + "queryLastCheckConfirDate", map1);
        if (lastCheckDate == null) return -3;//尚未进行过审批

        Map map2 = new HashMap();
        map2.put("orgCode", LoginParam.getOrg().getCode());
        map2.put("iyear", LoginParam.getIyear());
        map2.put("type", billType);
        map2.put("number", billNumber);
        map2.put("checkDate", lastCheckDate);
        List li = client.queryForList(NAMESPACE_FLOW + "queryFlowInfoListForCancelCheck", map2);
        if (li != null && !li.isEmpty()) return -2;//已有其他人进行了审批

        return 1;//可以撤销
    }

    /* 检查是否可撤销 审批
     * return  1 : 可撤销审批
     *        -2 : 已有其他人进行了审批
     *        -3 : 尚未进行过审批
     *        -1 : 数据库异常
     */
    @Override
    public int checkIfCancelAble(String billNumber) {
        int flag;
        SqlMapClient client = IbatisTemplate.getSqlMapClient();
        try {
            client.startTransaction();

            /* 检查是否可 撤销审批 */
            flag = checkIsCancelAble(client, billNumber, billType);

            client.commitTransaction();
        } catch (SQLException ex) {
            Logger.getLogger(BaseCheck.class.getName()).log(Level.SEVERE, null, ex);

            /* 遇到异常，返回false,注意：返回之前 finally 内的内容会执行，故不用担心会跳过finally */
            return -1;
        } finally {
            try {
                client.endTransaction();
            } catch (SQLException ex) {
                Logger.getLogger(BaseCheck.class.getName()).log(Level.SEVERE, null, ex);
            }
            System.out.println(" * * * " + " finlly " + "  * * * ");
        }

        return flag;
    }

    /* 所有审批信息 查询条件：number = #number# and type = #type# */
    @Override
    public List<FlowInfo> historyFlowInfo(String billNumber) {
        FlowInfo param = new FlowInfo(true);
        param.setType(billType);
        param.setNumber(billNumber);

        //return IbatisTemplate.queryForList(NAMESPACE_FLOW + "queryFlowInfoByNumberAndType", param);
        return IbatisTemplate.queryForList(NAMESPACE_FLOW + "queryFlowInfo_history", param);
    }

    /* flowModel 条件：type = #billType# and isPub = 1 and checkLevel = #checkLevel# */
    private List<FlowModel> getFlowModelListByLevel(int checkLevel) {
        List<FlowModel> templi = new ArrayList();

        for (FlowModel model : flowModelList) {
            if (model.getCheckLevel().intValue() == checkLevel) templi.add(model);
        }

        return templi;
    }

    /* 获取所有审批信息 */
    private List<FlowInfo> getFlowInfoList_all() {

        FlowInfo param = new FlowInfo(true);
        param.setType(billType);
        return IbatisTemplate.queryForList(NAMESPACE_FLOW + "queryFlowInfoListOfIsCheckedAll", param);
    }

    /* infoList 条件：number = #billNumber# and isCheck = 1
     * 注意：审批时，通过的，会将以前审批的 isCheck 置为 0；
     * 退回的也会将以前审批的 isCheck 置为 0，同时，保存的审批信息 isCheck 也为0；
     * 所有，isCheck = 1  ==> 是所有通过的审批信息
     */
    private List<FlowInfo> getFlowInfoListByNumber(String billNumber) {

        FlowInfo param = new FlowInfo(true);
        param.setType(billType);
        param.setNumber(billNumber);
        return IbatisTemplate.queryForList(NAMESPACE_FLOW + "queryFlowInfoListOfIsChecked", param);
    }

    /* 在事务中 查询最新审批信息列表 */
    private List<FlowInfo> getFlowInfoListInTransaction(SqlMapClient client, String billNumber) throws SQLException {

        FlowInfo param = new FlowInfo(true);
        param.setType(billType);
        param.setNumber(billNumber);
        return client.queryForList(NAMESPACE_FLOW + "queryFlowInfoListOfIsChecked", param);
    }

    /* 更新外部单据 的 flowMark */
    abstract void updateFlowMark(SqlMapClient client, String billNumber, String flowMark) throws SQLException;
}
